package it.disim.tlp.webReputation.logic;

import it.disim.tlp.webreputation.aggregatorplugin.AggregatorPlugin;
import it.disim.tlp.webreputation.aggregatorplugin.ManifestLoader;
import it.disim.tlp.webreputation.aggregatorplugin.PluginLoader;
import it.disim.tlp.webreputation.business.AbstractDataAggregatorFactory;
import it.disim.tlp.webreputation.business.ConnectorService;
import it.disim.tlp.webreputation.business.FactoryBuilder;
import it.disim.tlp.webreputation.business.model.Connector;
import it.disim.tlp.webreputation.exceptions.AggregatorLogger;
import it.disim.tlp.webreputation.threading.AggregatorThread;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;

import org.xml.sax.SAXException;

public class DataAggregatorNew {
	
	
	private AbstractDataAggregatorFactory factory;
	private ConnectorService cs;
	private Collection<Connector> connectors;
	private Collection<AggregatorThread> threads;
	
	public DataAggregatorNew(){
		/*factory instantiation*/
		this.factory = FactoryBuilder.getInstance();
		
		/*getting all connectors yet registered*/
		this.cs = factory.getConnectorService();
		this.connectors = cs.getAllConnectors();
		
		/*threads collection*/
		this.threads = new ArrayList<AggregatorThread>();
	}
	
	/**
	 * This method starts the server loading the already present
	 * plugins.
	 */
	public void start() {
		
		/*plugins loading at the beginning phase if any*/
		for(Connector c : connectors){
			
			/*manifest loading  and checking if it's valid*/
			ManifestLoader ml = null;
			try {
				ml = new ManifestLoader("plugins/"+c.getName()+"/Manifest.xml");
			} catch (SAXException | IOException e) {
				System.out.println("Manifest "+c.getName()+" is not valid... check log file inside logs directory.");
				AggregatorLogger.logging(c.getName(), e);
				continue;
			}
			
			System.out.println("Plugin "+ml.getName()+" loading...");
			
			/* plugin loading and checking if it's execute runtime errors during that phase*/
			PluginLoader pl = null;
			try{
				pl = new PluginLoader(c.getName(),ml.getJarName(),ml.getLibs(),ml.getClassName());
			}catch(Exception e){
				System.out.println("Plugin "+ml.getName()+" not loaded! Errors during loading... check log file inside logs directory.");
				AggregatorLogger.logging(ml.getName(), e);
				continue;
			}
			
			/*getting plugin instance*/
			AggregatorPlugin ap = pl.getPlugin();
			
			/*getting thread and starting it*/
			AggregatorThread at = new AggregatorThread(ap,ml,c);
			threads.add(at);
			at.start();
		}
		
	}
	
	/**
	 * this method add a new Connector loading its related plugin and starting a new thread.
	 * @param id Connector id.
	 */
	public void addConnector(int id){
		
		/*getting connector from id*/
		Connector c = new Connector(id);
		c = cs.getConnector(c);
		
		ManifestLoader ml = null;
		try {
			ml = new ManifestLoader("plugins/"+c.getName()+"/Manifest.xml");
		} catch (SAXException | IOException e) {
			System.out.println("Manifest "+c.getName()+" is not valid... check log file inside logs directory.");
			AggregatorLogger.logging(c.getName(), e);
			return;
		}
		
		System.out.println("Plugin "+ml.getName()+" loading...");
		
		PluginLoader pl = null;
		try {
			pl = new PluginLoader(c.getName(),ml.getJarName(),ml.getLibs(),ml.getClassName());
		} catch (Exception e){
			System.out.println("Plugin "+ml.getName()+" not loaded! Errors during loading... check log file inside logs directory.");
			AggregatorLogger.logging(ml.getName(), e);
			return;
		}
		
		AggregatorPlugin ap = pl.getPlugin();
		AggregatorThread at = new AggregatorThread(ap,ml,c);
		threads.add(at);
		at.start();	
	}
	
	/**
	 * this method remove a connector stopping the related thread.
	 * @param id connector id.
	 */
	public void remConnector(int id){
		for(AggregatorThread at : threads){
			if(at.getConnector().getId() == id){
				System.out.println("Plugin "+at.getManifestLoder().getName()+" removing...");
				at.interrupt();
				threads.remove(at);
				break;
			}
		}
	}
	

	/**
	 * This method is used to refresh the connector's updateInterval.
	 * The updateInterval is refreshed each time a thread performs its task.
	 * This method stops the thread and reloads it with the new one. It's
	 * useful when a thread has an updatInterval too large and we don't want
	 * to wait refreshing performed by the thread.  
	 * @param id connector id.
	 */
	public void upIntervalConnector(int id){
		for(AggregatorThread at: threads){
			if(at.getConnector().getId() == id){
				AggregatorPlugin ap = at.getAggregatorPlugin(); 
				ManifestLoader ml = at.getManifestLoder();
				
				/*getting connector from id*/
				Connector c = new Connector(id);
				c = cs.getConnector(c);
				
				System.out.println("Plugin "+ml.getName()+" interval updating to "+c.getUpdateInterval()+" minutes");
				at.interrupt();
				threads.remove(at);
				at = new AggregatorThread(ap,ml,c);
				threads.add(at);
				at.start();
			}
		}
	}

}
